
import asyncore
import asynchat
import socket
import sys
import thread
import traceback

from coffeetalk.protocol import ioml
from coffeetalk.utilities import iologger

class IOAsyncClientConnection(asynchat.async_chat):
    
    BUFFER_SIZE   = 32 * 1024
    CONNECTING    = 0
    LOGGEDIN      = 1
    
    def __init__(self,host,port,log):
        
        self.map = {}
        self.ac_in_buffer_size = IOAsyncClientConnection.BUFFER_SIZE
        self.ac_out_buffer_size = IOAsyncClientConnection.BUFFER_SIZE
        
        self.ac_in_buffer = ''
        self.ac_out_buffer = ''
        self.producer_fifo = asynchat.fifo()
        asyncore.dispatcher.__init__(self, map=self.map)

        self.host = host
        self.port = port
        self.log = log
        
        self.outgoinglock = thread.allocate_lock()
        self.clientstate = IOAsyncClientConnection.CONNECTING
        self.set_terminator(ioml.TERMINATOR)
        
        self.bufferincoming = ''
        self.bufferoutgoing = ''
        
        self.disconnect = False
     
    def connect_client(self):
        self.make_socket()
        asyncore.loop(timeout=0.01,use_poll=True,map=self.map)
        
    def make_socket(self):
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.connect((self.host,self.port))
   
    def handle_error(self):
        traceback.print_exc()
        type,value = sys.exc_info()[:2]
        self.log.log_error(iologger.ERROR,self.host,'""','""',iologger.current_function(depth=1),'handle_error_InternalError',str(type) + ':' + str(value))
         
    def handle_close(self):
        self.handle_disconnect()
        self.close()      
          
    def handle_connect(self):
        raise NotImplementedError('IOAsyncConnection.handle_connect: You must override or assign this function')
    
    def handle_disconnect(self):
        raise NotImplementedError, 'IOAsyncConnection.handle_disconnect: You must override or assign this function'
    
    def process_message(self,message):
        raise NotImplementedError, 'IOAsyncConnection.process_message: You must override or assign this function'

    def send_message(self,msg):
        self.outgoinglock.acquire()
        self.bufferoutgoing = self.bufferoutgoing + msg
        self.outgoinglock.release()
    
    def collect_incoming_data(self,data):
        self.bufferincoming = self.bufferincoming + data

    def found_terminator(self):
        incomingstring = self.bufferincoming + self.get_terminator()
        self.process_message(incomingstring)
        self.bufferincoming = ''
 
    def writable(self):
        if self.disconnect:
            self.close()
            
        self.outgoinglock.acquire()
        bufferlength = len(self.bufferoutgoing)
        self.outgoinglock.release()        
        return (bufferlength > 0)
  
    def handle_write(self):
        self.outgoinglock.acquire()
        sent = self.send(self.bufferoutgoing)
        self.bufferoutgoing = self.bufferoutgoing[sent:]
        self.outgoinglock.release()
   
    def handle_expt(self):
        pass
